////////////////////////////////////////
//	File Header
//	Author: Stephen Ringer | stephen.ringer@gmail.com
//	File: SAGAD3D.h
//
////////////////////////////////////////
#pragma once
////////////////////////////////////////
//	File Includes
#include <d3d9.h>
#include <d3dx9.h>
#include <windows.h>
#include "../SAGARenderer/SAGARenderDevice.h"
#include "../SAGAMath/zfx3d.h"
#include "SAGAD3D_vchache.h"
//	Library Includes
#pragma comment(lib, "vfw32.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "SAGAMath.lib")
//#pragma comment(lib, "../Release/SAGAMath.lib")
//
////////////////////////////////////////

////////////////////////////////////////
//	Macros
#define MAX_3DHWND 8
#define LPDIRECT3DVDECL9 LPDIRECT3DVERTEXDECLARATION9
#define IDENTITY(m) {memset(&m,0,sizeof(D3DMATRIX));m._11=m._22=m._33=m._44=1.0f;}
#define FVF_VERTEX  (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
#define FVF_PVERTEX (D3DFVF_XYZ)
#define FVF_LVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
#define FVF_CVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
#define FVF_T3VERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX3)
#define FVF_TVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1|D3DFVF_TEXCOORDSIZE3(0))
//
////////////////////////////////////////

////////////////////////////////////////
//	Global Function Prototypes
BOOL WINAPI DllEntryPoint(HINSTANCE hDll,
						  DWORD     fdwReason,
						  LPVOID    lpvRserved );
//
////////////////////////////////////////

////////////////////////////////////////
//	Struct Name: SAGACOMBOINFO
struct SAGACOMBOINFO 
{
	UINT       			nAdapter;				// Belongs to
	D3DDEVTYPE 			d3dDevType;				// HAL, SW, REF
	bool       			bWindowed;				// Windowed Mode

	D3DFORMAT  			fmtAdapter;				// PixelBuffer
	D3DFORMAT  			fmtBackBuffer;			// BackBuffer
	D3DFORMAT  			fmtDepthStencil;		// Z/Stencil Format

	DWORD				dwBehavior;				// Vertex Processing
	D3DMULTISAMPLE_TYPE	msType;					// Multi-sample type
};
//
////////////////////////////////////////

////////////////////////////////////////
//	Struct Name: SAGADEVICEINFO
//	Up to three for each adapter
struct SAGADEVICEINFO 
{
	UINT			nAdapter;        // Belongs to
	D3DDEVTYPE		d3dDevType;      // HAL, SW, REF
	D3DCAPS9		d3dCaps;         // Capabilities
	SAGACOMBOINFO	d3dCombo[80];    // Combo
	UINT			nNumCombo;       // Number of Combos
};
//
////////////////////////////////////////

////////////////////////////////////////
//	Struct Name: SAGAADAPTERINFO
struct SAGAADAPTERINFO 
{
	D3DADAPTER_IDENTIFIER9	d3dAdapterIdentifier;
	UINT					nAdapter;				// Which one
	D3DDISPLAYMODE			d3ddspmd[150];			// Display Modes
	UINT					nNumModes;				// Number of Modes
	SAGADEVICEINFO			d3dDevs[3];				// List of Devices
	UINT					nNumDevs;				// Number of Devices
};
//
////////////////////////////////////////

////////////////////////////////////////
//	Helper Functions

BOOL WINAPI DllEntryPoint( HINSTANCE hDll, DWORD fdwReason, LPVOID lpvRserved );
TCHAR*		D3DDevTypeToString(D3DDEVTYPE devType);
TCHAR*		D3DFormatToString(D3DFORMAT format);
TCHAR*		BehaviorTypeToString(DWORD vpt);
void*		GetSelectedItem(HWND hWnd);
void		AddItem(HWND hWnd, char *ch, void *pData);
bool		ContainsString(HWND hWnd, char *ch);
//
////////////////////////////////////////

////////////////////////////////////////
//	Class: SAGAD3DEnum
class SAGAD3DEnum 
{
public:
	SAGAD3DEnum(int nMinDepth, int nMinStencil) { m_nMinDepth=nMinDepth;  m_nMinStencil=nMinStencil; }
	~SAGAD3DEnum() {  }
	//	Enumerate all the stuff
	HRESULT Enum(HWND,HWND,HWND,HWND,HWND,HWND,HWND,FILE*);
	//	Combobox Selection Changed
	void	ChangedAdapter();
	void	ChangedDevice();
	void	ChangedAdapterFmt();
	void	ChangedWindowMode();
	//	Get Final Settings to Crank up
	void	GetSelections(SAGADEVICEINFO *pD, D3DDISPLAYMODE *dspmd, D3DFORMAT *fmtA, D3DFORMAT *fmtB);

	LPDIRECT3D9		m_pD3D;
	SAGAADAPTERINFO m_xAdapterInfo[10];
	DWORD			m_dwNumAdapters;

private:
	D3DDISPLAYMODE	m_dspmd;			//	Current Desktop Display Mode
	D3DFORMAT 		m_fmtAdapter[5];	//	List of Possible Adapter Formats
	UINT      		m_nNumFmt;			//	Adapter Formats Possible
	UINT      		m_nMinWidth;		//	Minimum Screen Width
	UINT      		m_nMinHeight;		//	Minimum Screen Height
	UINT      		m_nMinBits;			//	Minimum BackBuffer Bits
	UINT      		m_nMinDepth;		//	Minimum Depth Bits
	UINT      		m_nMinStencil;		//	Minimum Stencil Bits
	FILE			*m_pLog;			//	Log File Opened by SAGAD3D Class

	//	Handle to GUI items given from SAGAD3D dialog
	HWND 			m_hADAPTER;					//	Adapter ComboBox 
	HWND 			m_hMODE;						//	Mode ComboBox
	HWND 			m_hDEVICE;						//	Device ComboBox
	HWND 			m_hADAPTERFMT;					//	Adapter Format ComboBox
	HWND 			m_hBACKFMT;					//	BackBuffer Format ComboBox
	HWND 			m_hWND;						//	RadioButton Windowed
	HWND 			m_hFULL;						//	RadioButton FullScreen

	HRESULT	EnumAdapters(void);
	HRESULT EnumDevices(SAGAADAPTERINFO &);
	HRESULT EnumCombos(SAGADEVICEINFO &);

	UINT    GetBits(D3DFORMAT);
	HRESULT ConfirmDevice(D3DCAPS9*,DWORD,D3DFORMAT);
	bool    ConfirmDepthFmt(SAGACOMBOINFO*);
};
//
////////////////////////////////////////

////////////////////////////////////////
//	Class: SAGAD3D
//	Purpose: 
//		To encapsulate Direct3D functionality
class SAGAD3D : public SAGARenderDevice
{
private:
	SAGAD3DEnum				*m_pEnum;
	LPDIRECT3D9				m_pD3D;
	LPDIRECT3DDEVICE9		m_pDevice;
	D3DPRESENT_PARAMETERS	m_d3dpp;
	LPDIRECT3DSWAPCHAIN9	m_pChain[MAX_3DHWND];
	D3DCOLOR				m_ClearColor;
	bool					m_bIsSceneRunning;
	bool					m_bStencil;
	bool                  	m_bTextures;           	// use textures?
	D3DMATERIAL9          	m_StdMtrl;             	// standard material
	UINT                  	m_nActiveSkin;         	// currently active
	UINT                  	m_nActiveVShader;      	// currently active
	UINT                  	m_nActivePShader;      	// currently active
	LPD3DXFONT				*m_pFont;               // font objects
	UINT                  	m_nNumFonts;			// number of fonts
	D3DTEXTUREOP          	m_TOP[8];				// active tops

	D3DMATRIX m_mView2D,							// view matrix orthogonal
		m_mView3D,                         			// view matrix perspective
		m_mProj2D,                         			// orthogonal projection (whole screen)
		m_mProjP[4],                       			// perspective projection
		m_mProjO[4],                       			// orthogonal projection
		m_mWorld,                          			// active world matrix
		m_mViewProj,                       			// combo matrix for 3D
		m_mWorldViewProj;							// combo matrix for 3D


	LPDIRECT3DVDECL9      m_pDeclVertex;         	// declarations
	LPDIRECT3DVDECL9      m_pDeclPVertex;        	// declarations
	LPDIRECT3DVDECL9      m_pDeclLVertex;        	// declarations
	LPDIRECT3DVDECL9      m_pDeclCVertex;        	// declarations
	LPDIRECT3DVDECL9      m_pDecl3TVertex;       	// declarations
	LPDIRECT3DVDECL9      m_pDeclTVertex;        	// declarations

	LPDIRECT3DVERTEXSHADER9 m_pVShader[MAX_SHADER];
	LPDIRECT3DPIXELSHADER9  m_pPShader[MAX_SHADER];
	UINT                    m_nNumVShaders;
	UINT                    m_nNumPShaders;
	//	Start the API
	HRESULT Go();
	HRESULT OneTimeInit();


	// MISC STUFF
	void    Prepare2D();
	void    PrepareShaderStuff();
	void    CalcViewProjMatrix();
	void    CalcWorldViewProjMatrix();
	HRESULT CalcPerspProjMatrix(float fFOV, float fAspect, D3DMATRIX *m);
	void    CalcOrthoProjMatrix(float l, float r, float b, float t, float fN, float fF, int nStage);
	void	Log(char*, ...);
	void	LogDeviceCaps(D3DCAPS9 *pCaps);
public:
	SAGAD3D(HINSTANCE hDLL);
	~SAGAD3D();

	////////////////////////////////////////
	//	Manager Accessors
	SAGASkinManager* GetSkinManager() {return m_pSkinMan;}
	SAGAVertexCacheManager* GetVertexManager() {return m_pVertexMan;}
	//
	////////////////////////////////////////

	////////////////////////////////////////
	//	Initialization Functions
	HRESULT			Init(HWND, const HWND*, int, int, int, bool);
	HRESULT			InitWindowed(HWND, const HWND*, int, bool);
	BOOL CALLBACK	DlgProc(HWND, UINT, WPARAM, LPARAM);
	//
	////////////////////////////////////////

	////////////////////////////////////////
	//	Interface Functions
	void			Release();
	bool			IsRunning()					{return m_bRunning;}
	bool			IsWindowed()				{return m_bWindowed;}
	void			GetResolution(POINT *pPt)	{pPt->x = m_dwWidth;pPt->y = m_dwHeight;}
	UINT			GetActiveSkinID()			{return m_nActiveSkin;}
	void			SetActiveSkinID(UINT nID)	{m_nActiveSkin = nID;}
	UINT			GetActiveVShadID()			{return m_nActiveVShader;}
	UINT			GetActivePShadID()			{return m_nActivePShader;}
	HRESULT			CreateFont(const char*,int,bool,bool,bool,DWORD,UINT*);
	HRESULT			DrawText(UINT,int,int,UCHAR,UCHAR,UCHAR,char*,...);
	HRESULT			BeginRendering(bool, bool, bool);
	HRESULT			Clear(bool, bool, bool);
	HRESULT			UseWindow(UINT nHwnd);
	void			EndRendering();
	void    		FadeScreen(float, float, float, float);
	void			SetClearColor(float, float, float);
	void      		SetAmbientLight(float, float, float);
	void      		SetWorldTransform(const SAGAMatrix*);
	void      		SetBackfaceCulling(SAGARENDERSTATE);
	void      		SetDepthBufferMode(SAGARENDERSTATE);
	void      		SetStencilBufferMode(SAGARENDERSTATE,DWORD);
	void      		UseStencilShadowSettings(bool);
	SAGACOLOR  		GetWireColor() { return m_clrWire; }
	void      		SetShadeMode(SAGARENDERSTATE,float,const SAGACOLOR*);
	SAGARENDERSTATE	GetShadeMode() { return m_ShadeMode; }
	HRESULT			SetTextureStage(UCHAR, SAGARENDERSTATE);
	HRESULT			SetLight(const SAGALIGHT*, UCHAR);
	//	shader stuff
	HRESULT   		CreateVShader(const void *pData, UINT nSize, bool bLoadFromFile, bool bIsCompiled, UINT *pID);
	HRESULT   		CreatePShader(const void *pData, UINT nSize, bool bLoadFromFile, bool bIsCompiled, UINT *pID);
	HRESULT   		ActivateVShader(UINT, SAGAVERTEXID);
	HRESULT   		ActivatePShader(UINT);
	//	misc stuff
	void      		UseAdditiveBlending(bool);
	bool      		UsesAdditiveBlending()  { return m_bAdditive; }
	void      		UseColorBuffer(bool);
	bool      		UsesColorBuffer()  { return m_bColorBuffer; }
	void      		UseTextures(bool);
	bool      		UsesTextures() { return m_bTextures; }
	void      		UseShaders(bool);
	bool      		CanDoShaders() { return m_bCanDoShaders; }
	bool      		UsesShaders()  { return m_bUseShaders;   }
	HRESULT   		SetShaderConstant(SAGASHADERTYPE,SAGADATATYPE,UINT,UINT,const void*);
	HRESULT   		SetView3D(	const SAGAVector&, const SAGAVector&, const SAGAVector&, 
								const SAGAVector&);
	HRESULT   		SetViewLookAt(const SAGAVector&, const SAGAVector&, const SAGAVector&);
	void      		SetClippingPlanes(float, float);
	void      		SetOrthoScale(float, int);
	HRESULT   		SetMode(SAGAENGINEMODE, int n);
	HRESULT   		InitStage(float, SAGAVIEWPORT*, int n);
	HRESULT   		GetFrustum(SAGAPlane*);
	void      		Transform2Dto3D(const POINT&, SAGAVector*, SAGAVector*);
	POINT     		Transform3Dto2D(const SAGAVector&);
	SAGAVector 		Transform2Dto2D(UINT,float,const POINT*,SAGAAXIS);
	D3DTEXTUREOP	GetTOP(UCHAR n) { return m_TOP[n]; }
	//
	////////////////////////////////////////
};
//
////////////////////////////////////////